From 9d43538162796100f16026a6ee26d826dd82320f Mon Sep 17 00:00:00 2001
From: wwd <ericrock@foxmail.com>
Date: Mon, 16 May 2016 13:20:02 +0800
Subject: [PATCH] matrix: support Matrix starter kit

---
 arch/arm/configs/sun8iw7p1smp_defconfig  | 204 +++++++++++-
 arch/arm/mach-sunxi/sun8i.c              |  55 ++++
 drivers/char/Kconfig                     |  24 ++
 drivers/char/Makefile                    |   5 +
 drivers/char/matrix_gpio_int.c           | 309 +++++++++++++++++
 drivers/char/matrix_hcsr04.c             | 184 +++++++++++
 drivers/char/matrix_pwm.c                | 206 ++++++++++++
 drivers/char/matrix_rotary_encoder.c     | 205 ++++++++++++
 drivers/input/misc/adxl34x.c             |  33 +-
 drivers/staging/iio/Kconfig              |   1 +
 drivers/staging/iio/Makefile             |   1 +
 drivers/staging/iio/humidity/Kconfig     |  15 +
 drivers/staging/iio/humidity/Makefile    |   5 +
 drivers/staging/iio/humidity/dht11.c     | 366 +++++++++++++++++++++
 drivers/staging/iio/industrialio-core.c  |   1 +
 drivers/staging/iio/types.h              |   1 +
 drivers/w1/masters/Makefile              |   2 +-
 drivers/w1/masters/w1-gpio-board.c       |  59 ++++
 drivers/w1/masters/w1-gpio.c             |  13 +-
 .../sun8iw7p1/configs/nanopi-h3/sys_config.fex     |   9 +-
 21 files changed, 1684 insertions(+), 28 deletions(-)
 create mode 100644 drivers/char/matrix_gpio_int.c
 create mode 100644 drivers/char/matrix_hcsr04.c
 create mode 100644 drivers/char/matrix_pwm.c
 create mode 100644 drivers/char/matrix_rotary_encoder.c
 create mode 100644 drivers/staging/iio/humidity/Kconfig
 create mode 100644 drivers/staging/iio/humidity/Makefile
 create mode 100644 drivers/staging/iio/humidity/dht11.c
 create mode 100644 drivers/w1/masters/w1-gpio-board.c

diff --git a/arch/arm/configs/sun8iw7p1smp_defconfig b/arch/arm/configs/sun8iw7p1smp_defconfig
index bc86f3d..8cec706 100644
--- a/arch/arm/configs/sun8iw7p1smp_defconfig
+++ b/arch/arm/configs/sun8iw7p1smp_defconfig
@@ -1079,7 +1079,7 @@ CONFIG_BLK_DEV_CRYPTOLOOP=y
 # CONFIG_DS1682 is not set
 # CONFIG_TI_DAC7512 is not set
 CONFIG_UID_STAT=y
-# CONFIG_BMP085 is not set
+CONFIG_BMP085=m
 # CONFIG_USB_SWITCH_FSA9480 is not set
 # CONFIG_SUNXI_BROM_READ is not set
 # CONFIG_C2PORT is not set
@@ -1396,7 +1396,9 @@ CONFIG_INPUT_UINPUT=y
 # CONFIG_INPUT_GPIO is not set
 # CONFIG_INPUT_PCF8574 is not set
 # CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
-# CONFIG_INPUT_ADXL34X is not set
+CONFIG_INPUT_ADXL34X=m
+CONFIG_INPUT_ADXL34X_I2C=m
+# CONFIG_INPUT_ADXL34X_SPI is not set
 # CONFIG_INPUT_CMA3000 is not set
 # CONFIG_INPUT_SHAFT_ENCODER is not set
 
@@ -1461,6 +1463,10 @@ CONFIG_SERIAL_SUNXI_CONSOLE=y
 # CONFIG_DCC_TTY is not set
 # CONFIG_RAMOOPS is not set
 # CONFIG_SUNXI_D7S is not set
+CONFIG_MATRIX_GPIO_INT=m
+CONFIG_MATRIX_PWM=m
+CONFIG_MATRIX_ROTARY_ENCODER=m
+CONFIG_MATRIX_HCSR04=m
 # CONFIG_IR_CUT is not set
 CONFIG_SUNXI_CMATESET=y
 # CONFIG_SUNXI_ARISC_TEST is not set
@@ -1475,7 +1481,7 @@ CONFIG_SUNXI_SOC_INFO=y
 CONFIG_I2C=y
 CONFIG_I2C_BOARDINFO=y
 CONFIG_I2C_COMPAT=y
-# CONFIG_I2C_CHARDEV is not set
+CONFIG_I2C_CHARDEV=y
 # CONFIG_I2C_MUX is not set
 CONFIG_I2C_HELPER_AUTO=y
 CONFIG_I2C_ALGOBIT=y
@@ -1530,7 +1536,7 @@ CONFIG_SPI_SUNXI=y
 #
 # SPI Protocol Masters
 #
-# CONFIG_SPI_SPIDEV is not set
+CONFIG_SPI_SPIDEV=y
 # CONFIG_SPI_TLE62X0 is not set
 # CONFIG_HSI is not set
 
@@ -1602,7 +1608,29 @@ CONFIG_GPIO_SYSFS=y
 # MODULbus GPIO expanders:
 #
 CONFIG_GPIO_SUNXI=m
-# CONFIG_W1 is not set
+CONFIG_W1=y
+
+#
+# 1-wire Bus Masters
+#
+# CONFIG_W1_MASTER_DS2490 is not set
+# CONFIG_W1_MASTER_DS2482 is not set
+# CONFIG_W1_MASTER_DS1WM is not set
+CONFIG_W1_MASTER_GPIO=m
+
+#
+# 1-wire Slaves
+#
+CONFIG_W1_SLAVE_THERM=y
+# CONFIG_W1_SLAVE_SMEM is not set
+# CONFIG_W1_SLAVE_DS2408 is not set
+# CONFIG_W1_SLAVE_DS2423 is not set
+# CONFIG_W1_SLAVE_DS2431 is not set
+# CONFIG_W1_SLAVE_DS2433 is not set
+# CONFIG_W1_SLAVE_DS2760 is not set
+# CONFIG_W1_SLAVE_DS2780 is not set
+# CONFIG_W1_SLAVE_DS2781 is not set
+# CONFIG_W1_SLAVE_BQ27000 is not set
 # CONFIG_POWER_SUPPLY is not set
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
@@ -1677,7 +1705,7 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_NTC_THERMISTOR is not set
 # CONFIG_SENSORS_PC87360 is not set
 # CONFIG_SENSORS_PC87427 is not set
-# CONFIG_SENSORS_PCF8591 is not set
+CONFIG_SENSORS_PCF8591=m
 # CONFIG_PMBUS is not set
 # CONFIG_DA380 is not set
 # CONFIG_SENSORS_SHT15 is not set
@@ -1809,7 +1837,8 @@ CONFIG_BCMA_POSSIBLE=y
 # CONFIG_MFD_AAT2870_CORE is not set
 # CONFIG_MFD_RC5T583 is not set
 # CONFIG_REGULATOR is not set
-# CONFIG_PWM is not set
+CONFIG_PWM=y
+CONFIG_PWM_SUNXI=y
 CONFIG_MEDIA_SUPPORT=y
 
 #
@@ -2574,7 +2603,7 @@ CONFIG_RTC_INTF_DEV=y
 #
 # I2C RTC drivers
 #
-# CONFIG_RTC_DRV_DS1307 is not set
+CONFIG_RTC_DRV_DS1307=m
 # CONFIG_RTC_DRV_DS1374 is not set
 # CONFIG_RTC_DRV_DS1672 is not set
 # CONFIG_RTC_DRV_DS3232 is not set
@@ -2658,7 +2687,164 @@ CONFIG_SUNXI_DMA=y
 #
 # Microsoft Hyper-V guest support
 #
-# CONFIG_STAGING is not set
+CONFIG_STAGING=y
+# CONFIG_USBIP_CORE is not set
+# CONFIG_ECHO is not set
+# CONFIG_ASUS_OLED is not set
+# CONFIG_RTLLIB is not set
+# CONFIG_R8712U is not set
+# CONFIG_RTS5139 is not set
+# CONFIG_TRANZPORT is not set
+# CONFIG_LINE6_USB is not set
+# CONFIG_USB_SERIAL_QUATECH2 is not set
+# CONFIG_USB_SERIAL_QUATECH_USB2 is not set
+# CONFIG_VT6656 is not set
+CONFIG_IIO=y
+# CONFIG_IIO_ST_HWMON is not set
+# CONFIG_IIO_BUFFER is not set
+# CONFIG_IIO_TRIGGER is not set
+
+#
+# Accelerometers
+#
+# CONFIG_ADIS16201 is not set
+# CONFIG_ADIS16203 is not set
+# CONFIG_ADIS16204 is not set
+# CONFIG_ADIS16209 is not set
+# CONFIG_ADIS16220 is not set
+# CONFIG_ADIS16240 is not set
+# CONFIG_KXSD9 is not set
+# CONFIG_LIS3L02DQ is not set
+
+#
+# Analog to digital converters
+#
+# CONFIG_AD7291 is not set
+# CONFIG_AD7298 is not set
+# CONFIG_AD7606 is not set
+# CONFIG_AD799X is not set
+# CONFIG_AD7476 is not set
+# CONFIG_AD7887 is not set
+# CONFIG_AD7780 is not set
+# CONFIG_AD7793 is not set
+# CONFIG_AD7816 is not set
+# CONFIG_AD7192 is not set
+# CONFIG_ADT7310 is not set
+# CONFIG_ADT7410 is not set
+# CONFIG_AD7280 is not set
+# CONFIG_MAX1363 is not set
+
+#
+# Analog digital bi-direction converters
+#
+# CONFIG_ADT7316 is not set
+
+#
+# Capacitance to digital converters
+#
+# CONFIG_AD7150 is not set
+# CONFIG_AD7152 is not set
+# CONFIG_AD7746 is not set
+
+#
+# Digital to analog converters
+#
+# CONFIG_AD5064 is not set
+# CONFIG_AD5360 is not set
+# CONFIG_AD5380 is not set
+# CONFIG_AD5421 is not set
+# CONFIG_AD5624R_SPI is not set
+# CONFIG_AD5446 is not set
+# CONFIG_AD5504 is not set
+# CONFIG_AD5764 is not set
+# CONFIG_AD5791 is not set
+# CONFIG_AD5686 is not set
+# CONFIG_MAX517 is not set
+
+#
+# Direct Digital Synthesis
+#
+# CONFIG_AD5930 is not set
+# CONFIG_AD9832 is not set
+# CONFIG_AD9834 is not set
+# CONFIG_AD9850 is not set
+# CONFIG_AD9852 is not set
+# CONFIG_AD9910 is not set
+# CONFIG_AD9951 is not set
+
+#
+# Digital gyroscope sensors
+#
+# CONFIG_ADIS16060 is not set
+# CONFIG_ADIS16080 is not set
+# CONFIG_ADIS16130 is not set
+# CONFIG_ADIS16260 is not set
+# CONFIG_ADXRS450 is not set
+
+#
+# Humidity sensors
+#
+CONFIG_DHT11=m
+
+#
+# Network Analyzer, Impedance Converters
+#
+# CONFIG_AD5933 is not set
+CONFIG_INV_SENSOR=y
+
+#
+# Light sensors
+#
+# CONFIG_SENSORS_ISL29018 is not set
+# CONFIG_SENSORS_TSL2563 is not set
+# CONFIG_TSL2583 is not set
+
+#
+# Magnetometer sensors
+#
+# CONFIG_SENSORS_HMC5843 is not set
+
+#
+# Active energy metering IC
+#
+# CONFIG_ADE7753 is not set
+# CONFIG_ADE7754 is not set
+# CONFIG_ADE7758 is not set
+# CONFIG_ADE7759 is not set
+# CONFIG_ADE7854 is not set
+
+#
+# Resolver to digital converters
+#
+# CONFIG_AD2S90 is not set
+# CONFIG_AD2S1200 is not set
+# CONFIG_AD2S1210 is not set
+
+#
+# Triggers - standalone
+#
+# CONFIG_IIO_SIMPLE_DUMMY is not set
+# CONFIG_ZSMALLOC is not set
+# CONFIG_FB_SM7XX is not set
+# CONFIG_USB_ENESTORAGE is not set
+# CONFIG_BCM_WIMAX is not set
+# CONFIG_FT1000 is not set
+
+#
+# Speakup console speech
+#
+# CONFIG_SPEAKUP is not set
+# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set
+# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set
+# CONFIG_STAGING_MEDIA is not set
+
+#
+# Android
+#
+# CONFIG_ANDROID is not set
+# CONFIG_PHONE is not set
+# CONFIG_USB_WPAN_HCD is not set
+# CONFIG_SUNXIOOPS is not set
 CONFIG_CLKDEV_LOOKUP=y
 CONFIG_HAVE_CLK_PREPARE=y
 CONFIG_COMMON_CLK=y
diff --git a/arch/arm/mach-sunxi/sun8i.c b/arch/arm/mach-sunxi/sun8i.c
index 2c35075..7700d04 100755
--- a/arch/arm/mach-sunxi/sun8i.c
+++ b/arch/arm/mach-sunxi/sun8i.c
@@ -117,6 +117,40 @@ static struct i2c_board_info i2c_ina219_devs[] __initdata = {
 };
 #endif
 
+/*------------------------------------------------------------------------------
+ * Matrix device
+ */
+#if defined(CONFIG_INPUT_ADXL34X_I2C_MODULE)
+#define ADXL34X_I2C_BUS     (0)
+static struct i2c_board_info __initdata adxl34x_i2c_bdi = {
+	I2C_BOARD_INFO("adxl34x", 0x1d),
+	.irq	= -1,
+};
+#endif
+
+#if defined(CONFIG_BMP085_MODULE)
+#define BMP085_I2C_BUS (0)
+static struct i2c_board_info __initdata bmp085_i2c_bdi = {
+	I2C_BOARD_INFO("bmp085", 0x77),
+	.irq	= -1,
+};
+#endif
+
+#if defined(CONFIG_RTC_DRV_DS1307_MODULE)
+#define DS1307_I2C_BUS (0)
+static struct i2c_board_info __initdata ds1307_i2c_bdi = {
+	I2C_BOARD_INFO("ds1307", 0X68),
+	.irq	= -1,
+};
+#endif
+
+#if defined(CONFIG_SENSORS_PCF8591_MODULE)
+#define PCF8591_I2C_BUS (0)
+static struct i2c_board_info __initdata pcf8591_i2c_bdi = {
+        I2C_BOARD_INFO("pcf8591", 0x48),
+};
+#endif
+
 #if defined(CONFIG_ION) || defined(CONFIG_ION_MODULE)
 #define DEFAULT_SUNXI_ION_RESERVE_SIZE	96
 #define ION_CARVEOUT_INIT_MAX	4
@@ -461,6 +495,27 @@ static void __init sunxi_dev_init(void)
 	}
 	printk("ina219 device registered\n");
 #endif
+
+#if defined(CONFIG_INPUT_ADXL34X_I2C_MODULE)
+	printk("plat: add adxl34x device\n");
+	i2c_register_board_info(ADXL34X_I2C_BUS, &adxl34x_i2c_bdi, 1);
+#endif
+
+#if defined(CONFIG_BMP085_MODULE)
+	printk("plat: add bmp085 device\n");
+	i2c_register_board_info(BMP085_I2C_BUS, &bmp085_i2c_bdi, 1);
+#endif
+
+#if defined(CONFIG_RTC_DRV_DS1307_MODULE)
+	printk("plat: add ds1307 device\n");
+	i2c_register_board_info(DS1307_I2C_BUS, &ds1307_i2c_bdi, 1);
+#endif
+
+#if defined(CONFIG_SENSORS_PCF8591_MODULE)
+	printk("plat: add pcf8591 device\n");
+	i2c_register_board_info(PCF8591_I2C_BUS, &pcf8591_i2c_bdi, 1);
+#endif	
+
 #ifdef CONFIG_ANDROID_RAM_CONSOLE
 	/*	ram console	platform device initialize*/
 	ram_console_device_init();
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 6614788..5090528 100755
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -636,6 +636,30 @@ config SUNXI_D7S
 	---help---
 	  Sunxi display 7 segment for h3.
 
+config MATRIX_GPIO_INT
+	tristate "Matrix GPIO int sensor module"
+	default m
+	---help---
+	  Driver for Matrix GPIO int sensor module.
+
+config MATRIX_PWM
+	tristate "Matrix PWM module"
+	default m
+	---help---
+	  Driver for Matrix PWM module.
+
+config MATRIX_ROTARY_ENCODER
+	tristate "Matrix rotary encoder"
+	default m
+	---help---
+	  Driver for Matrix rotary encoder.
+
+config MATRIX_HCSR04
+	tristate "Matrix hcsr04"
+	default m
+	---help---
+	  Driver for Matrix hcsr04.
+	  
 source "drivers/char/sunxi_g2d/Kconfig"
 source "drivers/char/sunxi_ir_cut/Kconfig"
 source "drivers/char/cma_test/Kconfig"
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 399be2b..f0bda58 100755
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -82,3 +82,8 @@ obj-y				+= sunxi-di/
 obj-${CONFIG_ID}       += sunxi_id/
 obj-${CONFIG_RESET_KEY} += sunxi_key/
 obj-$(CONFIG_IR_CUT)   += sunxi_ir_cut/
+
+obj-$(CONFIG_MATRIX_GPIO_INT)	+= matrix_gpio_int.o
+obj-$(CONFIG_MATRIX_PWM)	+= matrix_pwm.o
+obj-$(CONFIG_MATRIX_ROTARY_ENCODER)	+= matrix_rotary_encoder.o
+obj-$(CONFIG_MATRIX_HCSR04) 	+= matrix_hcsr04.o
\ No newline at end of file
diff --git a/drivers/char/matrix_gpio_int.c b/drivers/char/matrix_gpio_int.c
new file mode 100644
index 0000000..cbe29ca
--- /dev/null
+++ b/drivers/char/matrix_gpio_int.c
@@ -0,0 +1,309 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/irq.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <linux/interrupt.h>
+#include <asm/uaccess.h>
+#include <linux/platform_device.h>
+#include <linux/cdev.h>
+#include <linux/miscdevice.h>
+#include <linux/gpio.h>
+
+#define DEVICE_NAME		"sensor"
+#define MAX_SENDEV_NUM      8
+
+struct sensor {
+    int gpio;
+    int int_type;
+};
+
+
+struct sensor_desc {
+    int ID;
+	int gpio;	
+    int int_type;
+	char *name;	
+	int is_used;
+	struct timer_list timer;
+};
+
+static size_t sensor_num = -1;				// number of sensor has been registered
+static int is_started = 0;
+static struct semaphore lock;
+
+static struct sensor_desc sensor_dev[MAX_SENDEV_NUM] = {
+	{ 0, -1, -1, "gpio_int_sensor1"},
+	{ 1, -1, -1, "gpio_int_sensor2"},
+	{ 2, -1, -1, "gpio_int_sensor3"},
+	{ 3, -1, -1, "gpio_int_sensor4"},
+	{ 4, -1, -1, "gpio_int_sensor5"},
+	{ 5, -1, -1, "gpio_int_sensor6"},
+	{ 6, -1, -1, "gpio_int_sensor7"},
+	{ 7, -1, -1, "gpio_int_sensor8"},
+};
+
+static volatile char sensor_dev_value[MAX_SENDEV_NUM] = {
+};
+
+static DECLARE_WAIT_QUEUE_HEAD(sensor_dev_waitq);
+
+static volatile int ev_press = 0;
+
+// static int timer_counter = 0;
+static void gpio_int_sensors_timer(unsigned long _data)
+{
+
+	struct sensor_desc *bdata = (struct sensor_desc *)_data;
+	int ID;
+	unsigned tmp = gpio_get_value(bdata->gpio);
+	ID = bdata->ID;
+
+	// printk("%s %d value=%d int_type=%d\n", __FUNCTION__, timer_counter++, tmp, bdata->int_type);
+	if (bdata->int_type == IRQ_TYPE_EDGE_RISING) {
+		if(tmp == 1) {
+			sensor_dev_value[ID] = 1;
+			ev_press = 1;
+			wake_up_interruptible(&sensor_dev_waitq);
+		}
+	} else if (bdata->int_type == IRQ_TYPE_EDGE_FALLING) {	
+		if(tmp == 0) {
+			sensor_dev_value[ID] = 1;
+			ev_press = 1;
+			wake_up_interruptible(&sensor_dev_waitq);
+		}
+	} else if (bdata->int_type == IRQ_TYPE_EDGE_BOTH) {
+		sensor_dev_value[ID] = tmp;
+		ev_press = 1;
+		wake_up_interruptible(&sensor_dev_waitq);
+	}
+}
+
+// static int int_counter=0;
+static irqreturn_t gpio_int_sensor_interrupt(int irq, void *dev_id)
+{
+	// printk("%s %d\n", __FUNCTION__, int_counter++);
+	struct sensor_desc *bdata = (struct sensor_desc *)dev_id;
+	mod_timer(&bdata->timer, jiffies + msecs_to_jiffies(100));
+	return IRQ_HANDLED;
+}
+
+static int start_all_sensor(void)
+{
+	int irq;
+	int i;
+	int err = 0;
+
+	for (i = 0; i < sensor_num; i++) {
+		if (!sensor_dev[i].gpio)
+			continue;
+
+		setup_timer(&sensor_dev[i].timer, gpio_int_sensors_timer,
+				(unsigned long)&sensor_dev[i]);
+
+		err = gpio_request(sensor_dev[i].gpio, "gpio_int_sensor");			
+		if (err) {
+			printk("%s gpio_request %d fail\n", __FUNCTION__, sensor_dev[i].gpio);
+            break;
+		}
+
+		irq = gpio_to_irq(sensor_dev[i].gpio);
+		err = request_irq(irq, gpio_int_sensor_interrupt, IRQ_TYPE_EDGE_FALLING, 
+				sensor_dev[i].name, (void *)&sensor_dev[i]);
+		if (err) {
+		    printk("%s request_irq %d fail\n", __FUNCTION__, irq);
+            break;
+		}
+	}
+
+	if (err) {
+		i--;
+		for (; i >= 0; i--) {
+			if (!sensor_dev[i].gpio)
+				continue;
+
+			gpio_free(sensor_dev[i].gpio);
+			irq = gpio_to_irq(sensor_dev[i].gpio);
+			disable_irq(irq);
+			free_irq(irq, (void *)&sensor_dev[i]);
+
+			del_timer_sync(&sensor_dev[i].timer);
+		}
+
+		return -EBUSY;
+	}
+
+	ev_press = 0;
+	return 0;
+}
+
+static int gpio_int_sensors_open(struct inode *inode, struct file *file)
+{
+	if (down_trylock(&lock))
+		return -EBUSY;
+    sensor_num = 0;
+    is_started = 0;
+	return 0;
+}
+
+static int stop_all_sensor(void)
+{
+	int irq, i;
+
+	for (i = 0; i < sensor_num; i++) {
+		if (!sensor_dev[i].gpio)
+			continue;
+
+		gpio_free(sensor_dev[i].gpio);
+		irq = gpio_to_irq(sensor_dev[i].gpio);
+		free_irq(irq, (void *)&sensor_dev[i]);
+
+		del_timer_sync(&sensor_dev[i].timer);
+	}
+	return 0;
+}
+
+static int gpio_int_sensors_close(struct inode *inode, struct file *file)
+{
+	// printk("%s sensor_num=%d is_started=%d\n",__FUNCTION__, sensor_num, is_started);
+	if (is_started && sensor_num > 0) {
+		stop_all_sensor();
+	}
+	sensor_num = -1;
+	is_started = 0;
+	ev_press = 0;
+	up(&lock);
+	return 0;
+}
+
+// static int read_counter = 0;
+static int gpio_int_sensors_read(struct file *filp, char __user *buff,
+		size_t count, loff_t *offp)
+{
+	unsigned long err;
+	int i = 0;
+
+	if (!ev_press) {
+		if (filp->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+		else
+			wait_event_interruptible(sensor_dev_waitq, ev_press);
+	}
+
+	ev_press = 0;
+
+	err = copy_to_user((void *)buff, (const void *)(&sensor_dev_value),
+			min(sensor_num, count));
+	for (i = 0; i<sensor_num; i++) {
+		sensor_dev_value[i] = 0;
+	}
+
+	return err ? -EFAULT : min(sensor_num, count);
+}
+
+static unsigned int gpio_int_sensors_poll( struct file *file,
+		struct poll_table_struct *wait)
+{
+	unsigned int mask = 0;
+
+	poll_wait(file, &sensor_dev_waitq, wait);
+	if (ev_press)
+		mask |= POLLIN | POLLRDNORM;
+
+	return mask;
+}
+
+static long gpio_int_sensors_ioctl(struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+#define ADD_SENSOR                  (0)
+#define DEL_SENSOR                  (1)
+#define START_ALL_SENSOR            (4)
+#define STOP_ALL_SENSOR             (8)
+
+	struct sensor sen;
+	void __user *argp;
+	int del_dev;
+	int ret;
+
+	//printk("%s cmd=%d\n", __func__, cmd);
+	switch(cmd) {
+		case ADD_SENSOR:
+			if (is_started != 0 || sensor_num >= MAX_SENDEV_NUM)
+				return -EBUSY;
+			argp = (void __user *)arg;
+			if (copy_from_user(&sen, argp, sizeof sen))
+				return -EINVAL;
+			sensor_dev[sensor_num].gpio = sen.gpio;
+			sensor_dev[sensor_num].int_type= sen.int_type;
+			sensor_num++;
+			break;
+		case DEL_SENSOR:
+			del_dev = (int)arg;
+			// printk("%s del_dev=%d\n", __func__, del_dev);
+			if (is_started != 0 || sensor_num <= 0 || del_dev != sensor_num) 
+				return -EINVAL;			
+			sensor_dev[sensor_num].gpio = -1;					
+			sensor_dev[sensor_num].int_type= -1;			
+			sensor_num--;
+			break;
+		case START_ALL_SENSOR:
+			if (is_started != 0 || sensor_num <= 0)
+				return -EBUSY;
+			if((ret = start_all_sensor()) < 0)
+				return ret;
+			is_started = 1;					
+			break;
+		case STOP_ALL_SENSOR:
+			if (is_started != 1 || sensor_num <= 0)
+				return -EBUSY;
+			stop_all_sensor();
+			is_started = 0;
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+
+static struct file_operations dev_fops = {
+	.owner		= THIS_MODULE,
+	.open		= gpio_int_sensors_open,
+	.release	= gpio_int_sensors_close, 
+	.read		= gpio_int_sensors_read,
+	.poll		= gpio_int_sensors_poll,
+	.unlocked_ioctl	= gpio_int_sensors_ioctl,
+};
+
+static struct miscdevice misc = {
+	.minor		= MISC_DYNAMIC_MINOR,
+	.name		= DEVICE_NAME,
+	.fops		= &dev_fops,
+};
+
+static int __init sensor_dev_init(void)
+{
+	printk("Matirx GPIO Int sensor init\n");
+	sema_init(&lock, 1);
+	return misc_register(&misc);
+}
+
+static void __exit sensor_dev_exit(void)
+{
+	printk("Matirx GPIO Int sensor exit\n");
+	misc_deregister(&misc);
+}
+
+module_init(sensor_dev_init);
+module_exit(sensor_dev_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("FriendlyARM Inc.");
+
diff --git a/drivers/char/matrix_hcsr04.c b/drivers/char/matrix_hcsr04.c
new file mode 100644
index 0000000..3f4961b
--- /dev/null
+++ b/drivers/char/matrix_hcsr04.c
@@ -0,0 +1,184 @@
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/hrtimer.h>
+#include <linux/ktime.h>
+#include <linux/device.h>
+#include <linux/kdev_t.h>
+#include <linux/interrupt.h> 
+#include <linux/sched.h>
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("DA BAI");
+MODULE_DESCRIPTION("Driver for HC-SR04 ultrasonic sensor");
+
+// #define HCSR04_IRQ_DEUBG
+struct HCSR04_resource {
+    int pin;
+};
+
+static int HCSR04_PIN = -1;
+static int hasResource = 0;
+static int irq_num = 0;
+static int irq_time[3];
+static int valid_value = 0;
+static DECLARE_WAIT_QUEUE_HEAD(hcsr_waitq);
+
+static int hcsr04_hwexit(void);
+static int hcsr04_hwinit(void);
+static ssize_t hcsr04_value_read(struct class *class, struct class_attribute *attr, char *buf);
+static irqreturn_t gpio_isr(int irq, void *data);
+
+static ssize_t hcsr04_value_write(struct class *class, struct class_attribute *attr, const char *buf, size_t len) 
+{
+    struct HCSR04_resource *res;
+    if (len == 4) {
+        res = (struct HCSR04_resource *)buf;
+
+        if (res->pin != -1 && hasResource == 0) {
+            HCSR04_PIN = res->pin;
+            if (hcsr04_hwinit() == -1) {
+                return -1;
+            }
+            hasResource = 1;
+        } else if (res->pin == -1 && hasResource == 1) {
+            if (hcsr04_hwexit() == -1) {
+                return -1;
+            }
+            hasResource = 0;
+        }
+    }
+    return len;
+}
+
+// This function is called when you read /sys/class/hcsr04/value
+static ssize_t hcsr04_value_read(struct class *class, struct class_attribute *attr, char *buf)
+{
+    int ret = -1;
+	int gpio_irq=-1;
+
+    if (hasResource == 0) {
+        return 0;
+    }    
+    irq_num = 0;
+	valid_value = 0;
+    gpio_direction_output(HCSR04_PIN, 0);
+    udelay(50);
+    gpio_set_value(HCSR04_PIN, 1);
+    udelay(50);
+    gpio_set_value(HCSR04_PIN, 0);
+    udelay(50);
+
+    ret = gpio_to_irq(HCSR04_PIN);
+    if (ret < 0) {
+        printk(KERN_ERR"%s fail to gpio_to_irq\n", __func__);
+        goto fail;
+    } else {
+        gpio_irq = ret;
+    }
+
+    ret = request_irq(gpio_irq, gpio_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING , "hc-sr04", NULL);
+    if (ret) {
+        printk(KERN_ERR"%s fail to request_irq\n", __func__);
+        goto fail;
+    }
+	
+	if(wait_event_interruptible_timeout(hcsr_waitq, valid_value, HZ) == 0) {
+		printk(KERN_ERR"%s timeout\n", __func__);
+		free_irq(gpio_irq, NULL);
+		goto fail;
+	}
+    free_irq(gpio_irq, NULL);
+#ifdef HCSR04_IRQ_DEUBG	    
+    printk("%s irq_time[1]=%d irq_time[0]=%d %d\n", __func__, irq_time[1], irq_time[0], irq_time[1]-irq_time[0]);
+#endif
+    return sprintf(buf, "%d\n", irq_time[1]-irq_time[0]);
+ fail:
+    return sprintf(buf, "%d\n", -1);;
+}
+
+// Sysfs definitions for hcsr04 class
+static struct class_attribute hcsr04_class_attrs[] = {
+        __ATTR(value,	S_IRUGO | S_IWUSR, hcsr04_value_read, hcsr04_value_write),
+        __ATTR_NULL,
+};
+
+// Name of directory created in /sys/class
+static struct class hcsr04_class = {
+        .name =			"hcsr04",
+        .owner =		THIS_MODULE, 
+        .class_attrs =	hcsr04_class_attrs,
+};
+
+// Interrupt handler on ECHO signal
+static irqreturn_t gpio_isr(int irq, void *data)
+{	
+	if (valid_value == 0) {	
+		if((irq_num == 0 && gpio_get_value(HCSR04_PIN) != 1) || 
+			(irq_num == 1 && gpio_get_value(HCSR04_PIN) != 0) ||
+			(irq_num == 2 && gpio_get_value(HCSR04_PIN) != 1)
+		) {
+			return IRQ_HANDLED;
+		}	
+	    irq_time[irq_num] = ktime_to_us(ktime_get());
+	    if(irq_num == 2) {
+#ifdef HCSR04_IRQ_DEUBG	    			
+			int i = 0;
+	    	for(i=0; i<3; i++)
+	    		printk("%d:%d\n", i, irq_time[i]);
+#endif      		
+			valid_value = 1;
+			wake_up_interruptible(&hcsr_waitq);
+	    	return IRQ_HANDLED;
+	    }		
+		irq_num++;
+	}
+    return IRQ_HANDLED;
+}
+
+static int hcsr04_hwinit(void)
+{	
+    int rtc;
+
+    rtc=gpio_request(HCSR04_PIN, "HCSR04");
+    if (rtc!=0) {
+        printk(KERN_INFO "Error %d\n",__LINE__);
+        goto fail;
+    }
+    return 0;
+
+    fail:
+    return -1;	
+}
+
+static int hcsr04_init(void)
+{		
+    printk(KERN_INFO "HC-SR04 driver v0.32 initializing.\n");
+
+    if (class_register(&hcsr04_class)<0) 
+        goto fail;
+    return 0;
+
+    fail:
+    return -1;
+
+}
+
+static int hcsr04_hwexit(void)
+{
+    gpio_free(HCSR04_PIN);
+    return 0;
+}
+
+static void hcsr04_exit(void)
+{
+    class_unregister(&hcsr04_class);
+    printk(KERN_INFO "HC-SR04 disabled.\n");
+}
+
+module_init(hcsr04_init);
+module_exit(hcsr04_exit);
+
diff --git a/drivers/char/matrix_pwm.c b/drivers/char/matrix_pwm.c
new file mode 100644
index 0000000..5cdd951
--- /dev/null
+++ b/drivers/char/matrix_pwm.c
@@ -0,0 +1,206 @@
+/*
+ * linux/drivers/char/matrix_pwm.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/fs.h>
+#include <linux/backlight.h>
+#include <linux/err.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+#include <linux/miscdevice.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+#include <mach/platform.h>
+#include <asm/uaccess.h>
+
+#define DEVICE_NAME				"pwm"
+#define PWM_NUM					(2)
+#define PWM_IOCTL_SET_FREQ		(0x1)
+#define PWM_IOCTL_STOP			(0x0)
+#define NS_IN_1HZ				(1000000000UL)
+
+static int is_pwm_working[PWM_NUM] = {0, 0};
+static struct pwm_device *matrix_pwm[PWM_NUM];
+static struct semaphore lock;
+
+static int pwm_set_freq(int index, int pin, unsigned long freq, int duty) 
+{
+	int ret=0;
+	int period_ns = NS_IN_1HZ / freq;
+	int duty_ns = period_ns  / 1000 * duty;
+
+	printk("%s %d %d\n", __func__, period_ns, duty_ns);
+	if ((ret = pwm_config(matrix_pwm[index], duty_ns, period_ns))) {
+		printk("fail to pwm_config\n");
+		return ret;
+	}
+	if ((ret = pwm_enable(matrix_pwm[index]))) {
+		printk("fail to pwm_enable\n");
+		return ret;
+	}
+	return ret;
+}
+
+static void pwm_stop(int index, int pin) 
+{
+	pwm_config(matrix_pwm[index], 0, NS_IN_1HZ / 100);
+	pwm_disable(matrix_pwm[index]);
+}
+
+static int matrix_pwm_hw_init(int index, int pin)
+{
+	int ret=0;
+
+#if 0
+	ret = gpio_request(pin, DEVICE_NAME);
+	if (ret) {
+		printk("request gpio %d for pwm failed\n", pin);
+		return ret;
+	}
+	gpio_direction_output(pin, 0);
+#endif
+
+	matrix_pwm[index] = pwm_request(index, DEVICE_NAME);
+	if (IS_ERR(matrix_pwm[index])) {
+		printk("request pwm%d failed\n", index);
+#if 0
+		gpio_free(pin);
+#endif
+		return -ENODEV;
+	}
+
+	pwm_stop(index, pin);
+	return ret;
+}
+
+static void matrix_pwm_hw_exit(int index,int pin) 
+{
+	pwm_stop(index, pin);
+	pwm_free(matrix_pwm[index]);
+#if 0
+	gpio_free(pin);
+#endif
+}
+
+static int matrix_pwm_open(struct inode *inode, struct file *file) {
+	if (!down_trylock(&lock))
+		return 0;
+	else
+		return -EBUSY;
+}
+
+static int matrix_pwm_close(struct inode *inode, struct file *file) {
+	up(&lock);
+	return 0;
+}
+
+static long matrix_pwm_ioctl(struct file *filep, unsigned int cmd,unsigned long arg)
+{
+	int pwm_id;
+	int param[3];
+	int gpio;
+	int freq;
+	int duty;
+	int ret;
+	
+	switch (cmd) {
+		case PWM_IOCTL_SET_FREQ:
+			if (copy_from_user(param, (void __user *)arg, sizeof(param)))
+				return -EINVAL;
+			gpio = param[0];
+			freq = param[1];
+			duty = param[2];
+			if (gpio == (SUNXI_PA_BASE + 5)) {
+				pwm_id = 0;
+			} else if (gpio == (SUNXI_PA_BASE + 6)) {
+				pwm_id = 1;
+			} else {
+				printk("Invalid pwm gpio %d\n", gpio);
+				return -EINVAL;
+			}
+
+			if (duty < 0 || duty > 1000) {
+				printk("Invalid pwm duty %d\n", duty);
+				return -EINVAL;
+			}
+			
+			if (is_pwm_working[pwm_id] == 1) {
+				matrix_pwm_hw_exit(pwm_id, gpio);
+			}
+			
+			if ((ret = matrix_pwm_hw_init(pwm_id, gpio))) {
+				return ret;
+			}
+			is_pwm_working[pwm_id] = 1;
+			if ((ret = pwm_set_freq(pwm_id, gpio, freq, duty))) {
+				return ret;
+			}
+			break;
+		case PWM_IOCTL_STOP:
+			if (copy_from_user(&gpio, (void __user *)arg, sizeof(gpio)))
+				return -EINVAL;
+			if (gpio == (SUNXI_PA_BASE + 5)) {
+				pwm_id = 0;
+			} else if (gpio == (SUNXI_PA_BASE + 6)) {
+				pwm_id = 1;
+			} else {
+				printk("Invalid pwm gpio %d\n", gpio);
+				return -EINVAL;
+			}
+			if (is_pwm_working[pwm_id] == 1) {
+				matrix_pwm_hw_exit(pwm_id, gpio);
+				is_pwm_working[pwm_id] = 0;
+			}
+			break;
+		default:
+			printk("%s unsupported pwm ioctl %d", __FUNCTION__, cmd);
+			break;
+	}
+
+	return 0;
+}
+
+static struct file_operations matrix_pwm_ops = {
+	.owner			= THIS_MODULE,
+	.open			= matrix_pwm_open,
+	.release		= matrix_pwm_close, 
+	.unlocked_ioctl	= matrix_pwm_ioctl,
+};
+
+static struct miscdevice matrix_misc_dev = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = DEVICE_NAME,
+	.fops = &matrix_pwm_ops,
+};
+
+static int __init matrix_pwm_init(void) 
+{
+	int ret;
+	ret = misc_register(&matrix_misc_dev);
+	printk("Matirx PWM init\n");
+
+	sema_init(&lock, 1);
+	return ret;
+}
+
+static void __exit matrix_pwm_exit(void) {
+	misc_deregister(&matrix_misc_dev);
+	printk("Matirx PWM exit\n");
+}
+
+module_init(matrix_pwm_init);
+module_exit(matrix_pwm_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("FriendlyARM Inc.");
+MODULE_DESCRIPTION("FriendlyARM Matrix PWM Driver");
+
diff --git a/drivers/char/matrix_rotary_encoder.c b/drivers/char/matrix_rotary_encoder.c
new file mode 100644
index 0000000..97fcb76
--- /dev/null
+++ b/drivers/char/matrix_rotary_encoder.c
@@ -0,0 +1,205 @@
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/hrtimer.h>
+#include <linux/ktime.h>
+#include <linux/device.h>
+#include <linux/kdev_t.h>
+#include <linux/interrupt.h> 
+#include <linux/sched.h>
+#include <linux/of_device.h>
+
+#include <asm/mach/irq.h>
+#include <mach/platform.h>
+
+static int has_init = 0;
+static int sw_pin = -1;			// func: int 
+static int sia_pin = -1;		// func: int
+static int sib_pin = -1;		// func: input
+static int sia_irq = -1;
+static int sw_irq = -1;
+static int counter = 0;
+static int sw = 0;
+
+static void rotary_sensor_hw_exit(void);
+static int rotary_sensor_hw_init(void );
+
+
+static ssize_t rotary_sensor_sw_read(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	if ( sw_pin != -1 && sia_pin != -1 && sib_pin != -1) {
+		return sprintf(buf, "%d\n", sw);
+    }
+    return -1;
+}
+
+static ssize_t rotary_sensor_value_read(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	if ( sw_pin != -1 && sia_pin != -1 && sib_pin != -1) {
+	    return sprintf(buf, "%d\n", counter);
+	}
+	return -1;
+}
+
+static ssize_t rotary_sensor_gpio_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%d,%d,%d\n", sw_pin, sia_pin, sib_pin);
+}
+
+static ssize_t rotary_sensor_gpio_store(struct device *device, struct device_attribute *attr, const char *buf, size_t count)
+{
+	if ( has_init ==0 ) {
+		sscanf(buf,"%d,%d,%d ", &sw_pin, &sia_pin, &sib_pin);
+		printk(KERN_ERR"buf=%s\n", buf);
+		if (rotary_sensor_hw_init()) {
+			has_init = 0;
+			return -1;
+		}	
+		else {
+			has_init = 1;
+		}	
+	} else {
+		rotary_sensor_hw_exit();
+		has_init = 0;
+	}	
+		
+	return count;
+}
+static struct device_attribute value_attr = __ATTR(value, S_IRUGO, rotary_sensor_value_read, NULL);
+static struct device_attribute sw_attr = __ATTR(sw,S_IRUGO, rotary_sensor_sw_read, NULL);
+static struct device_attribute gpio_attr = __ATTR(gpio, S_IRUGO|S_IWUGO, rotary_sensor_gpio_show, rotary_sensor_gpio_store);
+
+/* sys attribte group */
+static struct attribute *attrs[] = {
+	&value_attr.attr, &sw_attr.attr, &gpio_attr.attr, NULL,
+};
+
+static struct attribute_group attr_group = {
+		.attrs = (struct attribute **)attrs,
+};
+
+
+static irqreturn_t sw_isr(int irq, void *data)
+{	
+	if (gpio_get_value(sw_pin) == 1) {
+		sw = 0;
+	} else {
+		sw = 1;
+	}
+    // printk("%s sw=%d\n", __func__, sw);
+    return IRQ_HANDLED;
+}
+
+static irqreturn_t rotate_isr(int irq, void *data)
+{	
+	if (gpio_get_value(sib_pin) == 1) {
+		counter++;
+	} else {
+		counter--;
+	}
+    // printk("%s value=%d\n", __func__, counter);
+    return IRQ_HANDLED;
+}
+
+static void rotary_sensor_hw_exit(void)
+{
+	if (sia_irq != -1)
+	    free_irq(sia_irq, NULL);
+	if (sw_irq != -1)    
+		free_irq(sw_irq, NULL);
+	if (sib_pin != -1)
+		gpio_free(sib_pin);    
+	if (sia_pin != -1)	
+	    gpio_free(sia_pin);
+	if (sw_pin != -1)    
+	    gpio_free(sw_pin);	
+	sw_pin = sia_pin = sib_pin = -1;    
+}
+
+static int rotary_sensor_hw_init(void )
+{
+	int ret = -1;
+
+    ret = gpio_request(sw_pin, "sw");
+    if (ret) {
+        printk(KERN_ERR"gpio request sw_pin fail:%d\n", sw_pin);
+        return -1;
+    }
+    ret = gpio_request(sia_pin, "sia_pin");
+    if (ret) {
+        printk(KERN_ERR"gpio request sia_pin fail:%d\n", sia_pin);
+        goto fail_gpio_sw;
+    }
+    ret = gpio_request(sib_pin, "sib_pin");
+    if (ret) {
+        printk(KERN_ERR"gpio request sib_pin fail:%d\n", sia_pin);
+        goto fail_gpio_sia;
+    }
+
+    sw_irq = gpio_to_irq(sw_pin);
+    ret = request_irq(sw_irq, sw_isr, IRQ_TYPE_EDGE_BOTH, "rotary_sensor_sw", NULL);
+    if (ret) {
+        printk(KERN_ERR"%s fail to request_irq, gpio=%d irq=%d\n", __func__, sw_pin, sw_irq);
+        goto fail_gpio_sib;
+    }
+    
+    sia_irq = gpio_to_irq(sia_pin);
+    ret = request_irq(sia_irq, rotate_isr, IRQ_TYPE_EDGE_FALLING , "rotary_sensor_sia", NULL);
+    if (ret) {
+        printk(KERN_ERR"%s fail to request_irq, gpio=%d irq=%d\n", __func__, sia_pin, sia_irq);
+        goto fail_irq_sw;
+    }
+
+	gpio_direction_input(sib_pin);
+
+	return ret;
+
+fail_irq_sw:
+	free_irq(sw_irq, NULL);
+fail_gpio_sib:
+    gpio_free(sib_pin);
+fail_gpio_sia:
+	gpio_free(sia_pin);
+fail_gpio_sw:
+	gpio_free(sw_pin);
+    return ret;
+
+}
+static struct kobject *kobj = NULL;
+static int rotary_sensor_init(void)
+{		
+	int ret = 0;
+    printk(KERN_INFO "Matrix-rotary_encoder init.\n");
+	
+	kobj = kobject_create_and_add("rotary_encoder", &platform_bus.kobj);
+	if (!kobj) {
+		pr_err("%s: failed to kobject_create_and_add for rotary_encoder\n", __func__);
+		return -EINVAL;
+	}
+
+	ret = sysfs_create_group(kobj, &attr_group);
+	if (ret) {
+		pr_err("%s: failed to sysfs_create_group for rotary_encoder\n", __func__);
+		kobject_del(kobj);
+		return -EINVAL;
+	}
+	return ret;
+}
+
+static void rotary_sensor_exit(void)
+{
+    printk(KERN_INFO "Matrix-rotary_encoder exit.\n");
+    sysfs_remove_group(kobj, &attr_group);
+    kobject_put(kobj);
+	kobj = NULL;
+}
+
+module_init(rotary_sensor_init);
+module_exit(rotary_sensor_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("FriendlyARM");
+MODULE_DESCRIPTION("Driver for Matrix-Rotary_Sensor");
diff --git a/drivers/input/misc/adxl34x.c b/drivers/input/misc/adxl34x.c
index 1cf72fe..81fbe55 100644
--- a/drivers/input/misc/adxl34x.c
+++ b/drivers/input/misc/adxl34x.c
@@ -223,7 +223,7 @@ static const struct adxl34x_platform_data adxl34x_default_init = {
 	.free_fall_threshold = 8,
 	.free_fall_time = 0x20,
 	.data_rate = 8,
-	.data_range = ADXL_FULL_RES,
+	.data_range = ADXL_FULL_RES | INT_INVERT,
 
 	.ev_type = EV_ABS,
 	.ev_code_x = ABS_X,	/* EV_REL */
@@ -236,6 +236,9 @@ static const struct adxl34x_platform_data adxl34x_default_init = {
 	.watermark = 0,
 };
 
+static irqreturn_t adxl34x_irq(int irq, void *handle);
+static int adxl34x_read_without_int(int irq, void* handle);
+
 static void adxl34x_get_triple(struct adxl34x *ac, struct axis_triple *axis)
 {
 	short buf[3];
@@ -296,6 +299,14 @@ static void adxl34x_do_tap(struct adxl34x *ac,
 	adxl34x_send_key_events(ac, pdata, status, false);
 }
 
+static int adxl34x_read_without_int(int irq, void* handle)
+{
+	if (adxl34x_irq(irq, handle) != IRQ_HANDLED) {
+		return -1;
+	}
+	return 0;
+}
+
 static irqreturn_t adxl34x_irq(int irq, void *handle)
 {
 	struct adxl34x *ac = handle;
@@ -486,6 +497,10 @@ static ssize_t adxl34x_calibrate_show(struct device *dev,
 	struct adxl34x *ac = dev_get_drvdata(dev);
 	ssize_t count;
 
+	if (adxl34x_read_without_int(0, ac)) {
+		return 0;
+	}
+
 	mutex_lock(&ac->mutex);
 	count = sprintf(buf, "%d,%d,%d\n",
 			ac->hwcal.x * 4 + ac->swcal.x,
@@ -607,6 +622,9 @@ static ssize_t adxl34x_position_show(struct device *dev,
 	struct adxl34x *ac = dev_get_drvdata(dev);
 	ssize_t count;
 
+	if (adxl34x_read_without_int(0, ac)) {
+		return 0;
+	}
 	mutex_lock(&ac->mutex);
 	count = sprintf(buf, "(%d, %d, %d)\n",
 			ac->saved.x, ac->saved.y, ac->saved.z);
@@ -810,14 +828,16 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq,
 		ac->fifo_delay = false;
 
 	ac->bops->write(dev, POWER_CTL, 0);
-
+	// not use int
+#if 0
 	err = request_threaded_irq(ac->irq, NULL, adxl34x_irq,
-				   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+				   IRQF_TRIGGER_LOW | IRQF_ONESHOT,
 				   dev_name(dev), ac);
 	if (err) {
 		dev_err(dev, "irq %d busy?\n", ac->irq);
 		goto err_free_mem;
 	}
+#endif
 
 	err = sysfs_create_group(&dev->kobj, &adxl34x_attr_group);
 	if (err)
@@ -884,6 +904,13 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq,
 
 	ac->pdata.power_mode &= (PCTL_AUTO_SLEEP | PCTL_LINK);
 
+	__adxl34x_enable(ac);
+#if 0	
+	int start = 0x1D;
+	for(; start < 0x3C; start++) {
+		printk("reg[%x]=%x\n", start, AC_READ(ac, start));
+	}
+#endif
 	return ac;
 
  err_remove_attr:
diff --git a/drivers/staging/iio/humidity/Makefile b/drivers/staging/iio/humidity/Makefile
new file mode 100644
index 0000000..d5d36c0
--- /dev/null
+++ b/drivers/staging/iio/humidity/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for IIO humidity sensor drivers
+#
+
+obj-$(CONFIG_DHT11) += dht11.o
diff --git a/drivers/staging/iio/humidity/dht11.c b/drivers/staging/iio/humidity/dht11.c
new file mode 100644
index 0000000..a751a54
--- /dev/null
+++ b/drivers/staging/iio/humidity/dht11.c
@@ -0,0 +1,366 @@
+/*
+ * DHT11/DHT22 bit banging GPIO driver
+ *
+ * Copyright (c) Harald Geyer <harald@ccbib.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/printk.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/sysfs.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-sunxi.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/kthread.h>
+
+#include <mach/platform.h>
+
+#include "../iio.h"
+
+//#define DHT11_DEBUG 1
+#define DRIVER_NAME	"dht11"
+
+#define DHT11_DATA_VALID_TIME	2000000000  /* 2s in ns */
+
+#define DHT11_EDGES_PREAMBLE 4
+#define DHT11_BITS_PER_READ 40
+#define DHT11_EDGES_PER_READ (2*DHT11_BITS_PER_READ + DHT11_EDGES_PREAMBLE)
+
+/* Data transmission timing (nano seconds) */
+#define DHT11_START_TRANSMISSION	18  /* ms */
+#define DHT11_SENSOR_RESPONSE	80000
+#define DHT11_START_BIT		50000
+#define DHT11_DATA_BIT_LOW	27000
+#define DHT11_DATA_BIT_HIGH	70000
+
+#define DATA_START_FLAG_MIN 	(50000)
+#define DATA_START_FLAG_MAX 	(60000)
+#define DATA_ONE_MIN 			(65000)
+#define DATA_ONE_MAX 			(75000)
+#define DATA_ZERO_MIN 			(20000)
+#define DATA_ZERO_MAX 			(30000)
+
+
+struct dht11 {
+	struct device			*dev;
+
+	int				gpio;
+	int				irq;
+
+	struct completion		completion;
+
+	s64				timestamp;
+	int				temperature;
+	int				humidity;
+
+	/* num_edges: -1 means "no transmission in progress" */
+	int				num_edges;
+	struct {s64 ts; int value; }	edges[DHT11_EDGES_PER_READ];
+};
+
+static int gpio = -1;
+static int dht11_read_flag = 0;
+static unsigned char dht11_decode_byte(int *timing)
+{
+	unsigned char ret = 0;
+	int i;
+
+	for (i = 0; i < 8; ++i) {
+		ret <<= 1;
+		ret +=timing[i];
+	}
+
+	return ret;
+}
+
+static int dht11_decode(struct dht11 *dht11, int *timing)
+{
+	unsigned char temp_int, temp_dec, hum_int, hum_dec, checksum;
+
+#ifdef DHT11_DEBUG
+	int i = 0;
+	for(i=0; i<DHT11_BITS_PER_READ; i++)
+		printk(KERN_ERR"%02d %d\n", i, timing[i]);
+#endif
+	hum_int = dht11_decode_byte(timing);
+	hum_dec = dht11_decode_byte(&timing[8]);
+	temp_int = dht11_decode_byte(&timing[16]);
+	temp_dec = dht11_decode_byte(&timing[24]);
+	checksum = dht11_decode_byte(&timing[32]);
+
+#ifdef DHT11_DEBUG
+	printk(KERN_ERR"%d + %d + %d + %d = %d\n", hum_int, hum_dec, temp_int, temp_dec, checksum);
+#endif
+	if (((hum_int + hum_dec + temp_int + temp_dec) & 0xff) != checksum) {
+		dev_err(dht11->dev,
+			"checksum error %d %d %d %d %d\n",
+			hum_int, hum_dec, temp_int, temp_dec, checksum);
+		return -EIO;
+	}	
+
+	dht11->timestamp = iio_get_time_ns();
+	if (hum_int < 20) {  /* DHT22 */
+		dht11->temperature = (((temp_int & 0x7f) << 8) + temp_dec) *
+					((temp_int & 0x80) ? -100 : 100);
+		dht11->humidity = ((hum_int << 8) + hum_dec) * 100;
+	} else if (temp_dec == 0 && hum_dec == 0) {  /* DHT11 */
+		dht11->temperature = temp_int * 1000;
+		dht11->humidity = hum_int * 1000;
+	} else {
+		dev_err(dht11->dev,
+			"Don't know how to decode data: %d %d %d %d\n",
+			hum_int, hum_dec, temp_int, temp_dec);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int dht11_read_thread(void *__dev)
+{
+	struct dht11 *dht11 = (struct dht11 *)__dev;
+	int value = 0;
+	
+#ifdef DHT11_DEBUG
+	printk(KERN_INFO"%s start\n", __func__);
+#endif
+	if (gpio_direction_output(dht11->gpio, 0))
+		return -1;
+	msleep(DHT11_START_TRANSMISSION);
+	gpio_direction_input(dht11->gpio);
+	dht11->edges[dht11->num_edges].value = gpio_get_value(dht11->gpio);
+	dht11->edges[dht11->num_edges].ts = iio_get_time_ns();
+	while (dht11->num_edges < DHT11_EDGES_PER_READ && dht11_read_flag == 1) {
+		value = gpio_get_value(dht11->gpio);
+		if (dht11->edges[dht11->num_edges].value != value) {
+			dht11->num_edges++;
+			dht11->edges[dht11->num_edges].ts = iio_get_time_ns();
+			dht11->edges[dht11->num_edges].value = value;
+			if (dht11->num_edges == DHT11_EDGES_PER_READ)
+				complete(&dht11->completion);
+		}
+	}
+	return 0;
+}
+
+static int dht11_read_raw(struct iio_dev *iio_dev,
+			const struct iio_chan_spec *chan,
+			int *val, int *val2, long m)
+{
+	struct dht11 *dht11 = iio_priv(iio_dev);
+	int ret;
+	int i, j;
+	int timing[DHT11_BITS_PER_READ], time;
+	struct task_struct *th;
+
+	if (dht11->timestamp + DHT11_DATA_VALID_TIME < iio_get_time_ns()) {
+		dht11->num_edges = 0;
+		dht11->completion.done = 0;
+		th = kthread_create(dht11_read_thread, dht11, "dht11-read");
+		if (IS_ERR(th)) {
+			ret = -1;
+			goto err;
+		}
+		dht11_read_flag = 1;
+		wake_up_process(th);
+		ret = wait_for_completion_killable_timeout(&dht11->completion, HZ);
+		dht11_read_flag = 0;
+		if(th)
+			kthread_stop(th);
+		if (ret == 0) {
+			dev_err(&iio_dev->dev, "dht11 read raw timeout\n");
+			ret = -1;
+			//goto err;
+		}	
+		for(i=0,j=0; i<dht11->num_edges; i++) {
+			if (i != 0) {
+#ifdef DHT11_DEBUG
+				printk(KERN_DEBUG"%02d ts=%lld value=%d pass=%lld\n", i, dht11->edges[i].ts, dht11->edges[i].value, dht11->edges[i].ts - dht11->edges[i-1].ts);
+#endif
+				time = dht11->edges[i].ts - dht11->edges[i-1].ts;
+			}
+			if (i > 3) {
+				if ((i%2) == 0) {	// one bit start always about 50us
+					if (time<DATA_START_FLAG_MIN || time>DATA_START_FLAG_MAX) {
+						printk(KERN_ERR"bit start without 50us, time=%d\n", time);
+						ret = -EINVAL;
+						goto err;
+					}	
+				} else {
+					time = dht11->edges[i].ts - dht11->edges[i-1].ts;
+					if (time > DATA_ZERO_MIN && time < DATA_ZERO_MAX)
+						timing[j] = 0;
+					else if (time > DATA_ONE_MIN && time < DATA_ONE_MAX)
+						timing[j]= 1;
+					else {
+						printk(KERN_ERR"bit value is not 1 or 0, time=%d\n", time);
+						ret = -EINVAL;
+						goto err;
+					}
+					j++;
+				}
+			}
+		}
+
+		ret = dht11_decode(dht11, timing);
+		if (ret)
+			goto err;
+	}
+
+	ret = IIO_VAL_INT;
+	if (chan->type == IIO_TEMP)
+		*val = dht11->temperature;
+	else if (chan->type == IIO_HUMIDITYRELATIVE)
+		*val = dht11->humidity;
+	else
+		ret = -EINVAL;
+err:
+	dht11->num_edges = -1;
+	return ret;
+}
+
+static const struct iio_info dht11_iio_info = {
+	.driver_module		= THIS_MODULE,
+	.read_raw		= dht11_read_raw,
+};
+
+static const struct iio_chan_spec dht11_chan_spec[] = {
+	{ 
+		.type = IIO_TEMP,
+	  	.processed_val = IIO_PROCESSED,
+	},
+	{ 
+		.type = IIO_HUMIDITYRELATIVE,
+	  	.processed_val = IIO_PROCESSED,
+	}
+};
+
+static const struct of_device_id dht11_dt_ids[] = {
+	{ .compatible = "dht11", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, dht11_dt_ids);
+
+static int dht11_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct dht11 *dht11;
+	struct iio_dev *iio;
+	int ret = -1;
+
+	iio = iio_allocate_device(sizeof(*dht11));
+	if (!iio) {
+		dev_err(dev, "Failed to allocate IIO device\n");
+		return -ENOMEM;
+	}
+
+	dht11 = iio_priv(iio);
+	dht11->dev = dev;
+	dht11->gpio = gpio;
+
+	ret = gpio_request(dht11->gpio, pdev->name);
+	if (ret)
+		return ret;
+
+	dht11->timestamp = iio_get_time_ns() - DHT11_DATA_VALID_TIME - 1;
+	dht11->num_edges = -1;
+
+	platform_set_drvdata(pdev, iio);
+
+	init_completion(&dht11->completion);
+	iio->name = pdev->name;
+	iio->dev.parent = &pdev->dev;
+	iio->info = &dht11_iio_info;
+	iio->modes = INDIO_DIRECT_MODE;
+	iio->channels = dht11_chan_spec;
+	iio->num_channels = ARRAY_SIZE(dht11_chan_spec);
+
+	return iio_device_register(iio);
+}
+
+static int dht11_remove(struct platform_device *pdev)
+{
+	struct iio_dev *iio = platform_get_drvdata(pdev);
+	struct dht11 *dht11 = iio_priv(iio);
+
+	iio_device_unregister(iio);
+	gpio_free(dht11->gpio);
+	iio_free_device(iio);
+	return 0;
+}
+
+static struct platform_driver dht11_driver = {
+	.driver = {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+		.of_match_table = dht11_dt_ids,
+	},
+	.probe  = dht11_probe,
+	.remove = dht11_remove,
+};
+
+void matrix_dht11_device_release(struct device *dev)
+{
+}
+
+static struct platform_device dht11_device = {
+	.name			= "dht11",
+	.id				= -1,
+	.num_resources	= 0,
+	.dev = {        
+        	.release 			= matrix_dht11_device_release,
+        }
+};
+
+static int __init dht11_init(void)
+{
+	int ret = -1;
+	
+	printk("plat: add device matrix-dht11, gpio=%d\n", gpio);
+	if ((ret = platform_device_register(&dht11_device))) {
+		return ret;
+	}
+
+	if ((ret = platform_driver_register(&dht11_driver))) {
+		platform_device_unregister(&dht11_device);
+	}
+	return ret;
+}
+
+static void __exit dht11_exit(void)
+{
+	platform_driver_unregister(&dht11_driver);
+	platform_device_unregister(&dht11_device);
+	gpio = -1;
+}
+
+module_init(dht11_init);
+module_exit(dht11_exit);
+MODULE_AUTHOR("Harald Geyer <harald@ccbib.org>");
+MODULE_DESCRIPTION("DHT11 humidity/temperature sensor driver");
+MODULE_LICENSE("GPL v2");
+module_param(gpio, int, 0644);
diff --git a/drivers/staging/iio/industrialio-core.c b/drivers/staging/iio/industrialio-core.c
index e16500a..7e4421e 100755
--- a/drivers/staging/iio/industrialio-core.c
+++ b/drivers/staging/iio/industrialio-core.c
@@ -68,6 +68,7 @@ static const char * const iio_chan_type_name_spec[] = {
 	[IIO_ANGL] = "angl",
 	[IIO_TIMESTAMP] = "timestamp",
 	[IIO_CAPACITANCE] = "capacitance",
+	[IIO_HUMIDITYRELATIVE] = "humidityrelative",
 	[IIO_QUATERNION] = "quaternion",
 };
 
diff --git a/drivers/staging/iio/types.h b/drivers/staging/iio/types.h
index 291c783..616c141 100755
--- a/drivers/staging/iio/types.h
+++ b/drivers/staging/iio/types.h
@@ -27,6 +27,7 @@ enum iio_chan_type {
 	IIO_ANGL,
 	IIO_TIMESTAMP,
 	IIO_CAPACITANCE,
+	IIO_HUMIDITYRELATIVE,
 	IIO_QUATERNION,
 };
 
diff --git a/drivers/w1/masters/Makefile b/drivers/w1/masters/Makefile
index c5a3e96..88ee685 100644
--- a/drivers/w1/masters/Makefile
+++ b/drivers/w1/masters/Makefile
@@ -8,5 +8,5 @@ obj-$(CONFIG_W1_MASTER_DS2482)		+= ds2482.o
 obj-$(CONFIG_W1_MASTER_MXC)		+= mxc_w1.o
 
 obj-$(CONFIG_W1_MASTER_DS1WM)		+= ds1wm.o
-obj-$(CONFIG_W1_MASTER_GPIO)		+= w1-gpio.o
+obj-$(CONFIG_W1_MASTER_GPIO)		+= w1-gpio.o w1-gpio-board.o
 obj-$(CONFIG_HDQ_MASTER_OMAP)		+= omap_hdq.o
diff --git a/drivers/w1/masters/w1-gpio-board.c b/drivers/w1/masters/w1-gpio-board.c
new file mode 100644
index 0000000..11aa1e4
--- /dev/null
+++ b/drivers/w1/masters/w1-gpio-board.c
@@ -0,0 +1,59 @@
+/*
+ * w1-gpio-board.c - Board driver for GPIO w1 bus master
+ *
+ * Copyright (C) 2016 FriendlyARM (www.friendlyarm.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/w1-gpio.h>
+#include <linux/gpio.h>
+
+#include <mach/platform.h>
+
+static int gpio = -1;
+module_param(gpio, int, 0644);
+
+
+static struct w1_gpio_platform_data w1_gpio_pdata = {
+	.pin		= -1,
+	.is_open_drain	= 0,
+};
+
+static void w1_device_release(struct device *dev) {
+	// nothing here yet
+}
+
+static struct platform_device matrix_w1_device = {
+	.name		= "w1-gpio",
+	.id			= -1,
+	.dev		= {
+		.release	= w1_device_release,
+		.platform_data	= &w1_gpio_pdata,
+	}
+};
+
+
+static int __init w1_gpio_board_init(void)
+{
+	w1_gpio_pdata.pin = gpio;
+	printk("plat: add device w1-gpio, gpio=%d\n", w1_gpio_pdata.pin);
+	return platform_device_register(&matrix_w1_device);
+}
+
+static void __exit w1_gpio_board_exit(void)
+{
+	platform_device_unregister(&matrix_w1_device);
+}
+
+module_init(w1_gpio_board_init);
+module_exit(w1_gpio_board_exit);
+
+MODULE_DESCRIPTION("Board driver for GPIO w1 bus master");
+MODULE_AUTHOR("FriendlyARM");
+MODULE_LICENSE("GPL");
diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c
index df600d1..28f8d7d 100644
--- a/drivers/w1/masters/w1-gpio.c
+++ b/drivers/w1/masters/w1-gpio.c
@@ -42,7 +42,7 @@ static u8 w1_gpio_read_bit(void *data)
 	return gpio_get_value(pdata->pin) ? 1 : 0;
 }
 
-static int __init w1_gpio_probe(struct platform_device *pdev)
+static int w1_gpio_probe(struct platform_device *pdev)
 {
 	struct w1_bus_master *master;
 	struct w1_gpio_platform_data *pdata = pdev->dev.platform_data;
@@ -56,8 +56,10 @@ static int __init w1_gpio_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	err = gpio_request(pdata->pin, "w1");
-	if (err)
+	if (err) {
+		dev_err(&pdev->dev, "failed to request GPIO %d\n", pdata->pin);
 		goto free_master;
+	}
 
 	master->data = pdata;
 	master->read_bit = w1_gpio_read_bit;
@@ -89,7 +91,7 @@ static int __init w1_gpio_probe(struct platform_device *pdev)
 	return err;
 }
 
-static int __exit w1_gpio_remove(struct platform_device *pdev)
+static int w1_gpio_remove(struct platform_device *pdev)
 {
 	struct w1_bus_master *master = platform_get_drvdata(pdev);
 	struct w1_gpio_platform_data *pdata = pdev->dev.platform_data;
@@ -136,14 +138,15 @@ static struct platform_driver w1_gpio_driver = {
 		.name	= "w1-gpio",
 		.owner	= THIS_MODULE,
 	},
-	.remove	= __exit_p(w1_gpio_remove),
+	.probe = w1_gpio_probe,
+	.remove	= w1_gpio_remove,
 	.suspend = w1_gpio_suspend,
 	.resume = w1_gpio_resume,
 };
 
 static int __init w1_gpio_init(void)
 {
-	return platform_driver_probe(&w1_gpio_driver, w1_gpio_probe);
+	return platform_driver_register(&w1_gpio_driver);
 }
 
 static void __exit w1_gpio_exit(void) 
